home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1991 / 08 / cppcont.asc < prev    next >
Text File  |  1991-07-23  |  16KB  |  668 lines

  1. _GENERIC CONTAINERS IN C++_
  2. by Andrew Davidson
  3.  
  4.  
  5. /*
  6.  * Generic list
  7.  *
  8.  * by A. E. Davidson 12/90
  9.  *
  10.  * Overview
  11.  *
  12.  * USES
  13.  * to declare a generic list of class
  14.  * foo items and a generic list of class 
  15.  * bar items
  16.  *
  17.  * #include "genriclt.hh"
  18.  * DeclareList(Foo);
  19.  * DeclareList(Bar);
  20.  *
  21.  * main()
  22.  * {
  23.  * class foo;
  24.  * class bar;
  25.  * GenList(foo) genListOfFoo;
  26.  * GenList(bar) genListOfBar;
  27.  * GenIter
  28.  *
  29.  * REQUIREMENTS / ASSUMPTIONS
  30.  * The generic list does not manage
  31.  * the items memory. It is up to the
  32.  * user to free them
  33.  *
  34.  * the function GenList::RemoveItem()
  35.  * takes a pointer to a member function.
  36.  * this funciton should return true is found
  37.  * else false. GenList::RemoveItem will not 
  38.  * compile on my machine if the member 
  39.  * fuction is inlined. it gives a signal 6 error message
  40.  *
  41.  * NOTES
  42.  * never use new to create a list or an iter!
  43.  *
  44.  *
  45.  */
  46.  
  47. #include <generic.h>
  48.  
  49. #ifndef GENERIC_LIST_HH
  50. #define GENERIC_LIST_HH
  51.  
  52. /*
  53.  * these macro's should be used 
  54.  * any where you need to reffer to
  55.  * the generic list, item, or iter classes
  56.  *
  57.  * PTAMF: Pointer to a Member Function
  58.  */
  59. #define PTAMF(CLASS_TAG)   name2(CLASS_TAG,PTAMF)
  60. #define GenItem(CLASS_TAG) name2(CLASS_TAG,GenItem)
  61. #define GenList(CLASS_TAG) name2(CLASS_TAG,GenList)
  62. #define GenIter(CLASS_TAG) name2(CLASS_TAG,GenIter)
  63.  
  64. /*----------------------------- class Item ---------------------------*/
  65. /*
  66.  * GenItem(CLASS_TAG) is a private
  67.  * class. It can only be created by
  68.  * be the member functions of GenList(CLASS_TAG)
  69.  * and GenIter(CLASS_TAG)
  70.  */
  71.  
  72. #define GenItemdeclare(CLASS_TAG)                           \
  73. class GenItem(CLASS_TAG)                          \
  74. {                                      \
  75.   GenItem(CLASS_TAG) *next;                                 \
  76.   CLASS_TAG &item;                                     \
  77.   GenItem(CLASS_TAG)(CLASS_TAG &i) : item(i)                 \
  78.     {next = NULL;}                              \
  79.   GenItem(CLASS_TAG)(CLASS_TAG &i, GenItem(CLASS_TAG) *n) : item(i)      \
  80.     {next = n; }                              \
  81.   ~GenItem(CLASS_TAG)()                          \
  82.     {;}                                            \
  83.   friend GenList(CLASS_TAG);                                 \
  84.   friend GenIter(CLASS_TAG);                          \
  85. }    
  86.  
  87. /*---------------------------- class List ---------------------------*/    
  88. #define GenListdeclare(CLASS_TAG)                              \
  89. class GenList(CLASS_TAG)                                \
  90. {                                            \
  91.   GenItem(CLASS_TAG) *hd;                                \
  92.  public:                                        \
  93.   GenList(CLASS_TAG)(GenItem(CLASS_TAG) *n = NULL)             \
  94.     { hd = n;}                                   \
  95.   GenList(CLASS_TAG)(const CLASS_TAG &i)                  \
  96.     {hd = NULL; insert(i);}                                 \
  97.   ~GenList(CLASS_TAG)()                             \
  98.     {Clear();}                                  \
  99.   void Clear(void)                             \
  100.     {                                            \
  101.       GenItem(CLASS_TAG) *pt;                                \
  102.       while (hd)                                    \
  103.     {                                        \
  104.       pt = hd;                                    \
  105.       hd = hd->next;                                \
  106.       delete pt;                                    \
  107.     }                                        \
  108.     }                                                   \
  109.   GenList(CLASS_TAG)(const GenList(CLASS_TAG) &seq) {hd = seq.hd;}      \
  110.   GenList(CLASS_TAG) operator = (const GenList(CLASS_TAG) &other)     \
  111.     {                                     \
  112.       hd = other.hd;                              \
  113.       return *this;                                    \
  114.     }                                     \
  115.   void insert(CLASS_TAG &i){ hd = new GenItem(CLASS_TAG)(i, hd); }      \
  116.   void append(CLASS_TAG &i)                         \
  117.     {                                     \
  118.       for (GenItem(CLASS_TAG) *pt = hd; pt && pt ->next; pt = pt->next)     \
  119.     ;                                 \
  120.       if (pt)                                  \
  121.     {                                 \
  122.       GenItem(CLASS_TAG) *tmp = new GenItem(CLASS_TAG)(i);          \
  123.       pt->next = tmp;                         \
  124.     }                                    \
  125.       else insert(i);                             \
  126.     }                                      \
  127.                                      \
  128.   void removeItem(PTAMF(CLASS_TAG) found, CLASS_TAG &obj)               \
  129.     {                                     \
  130.       GenItem(CLASS_TAG) *prev, *rem;                     \
  131.                                            \
  132.       prev = NULL;                             \
  133.       rem = hd;                                 \
  134.       while( rem && !(obj.*found)(rem->item) )                 \
  135.         {                                 \
  136.       prev = rem;                             \
  137.       rem = rem->next;                         \
  138.     }                                 \
  139.       if (rem)                                    \
  140.         {                                 \
  141.           if (prev)                             \
  142.         prev->next = rem->next;                     \
  143.           else                             \
  144.         hd = rem->next;                         \
  145.           delete rem;                                \
  146.         }                                 \
  147.     }                                     \
  148.   friend GenIter(CLASS_TAG);                         \
  149. }
  150.  
  151.  
  152.  
  153. /*------------------------------- class Iter ---------------------------*/
  154.   /* 
  155.    * interate over entire list 
  156.    * CLASS_TAG *operator()()
  157.    */
  158.   
  159. #define GenIterdeclare(CLASS_TAG)                     \
  160. class GenIter(CLASS_TAG)                         \
  161. {                                      \
  162.   GenItem(CLASS_TAG) *current;                        \
  163.  public:                                 \
  164.   GenIter(CLASS_TAG)(GenList(CLASS_TAG) &ilist)                \
  165.     { current = ilist.hd; }                        \
  166.   GenIter(CLASS_TAG)(GenIter(CLASS_TAG) &other)                \
  167.     { current = other.current; }                         \
  168.   ~GenIter(CLASS_TAG)()                         \
  169.     {;}                                 \
  170.   GenIter(CLASS_TAG) operator = (GenList(CLASS_TAG) &ilist)         \
  171.     { current = ilist.hd; return *this; }                 \
  172.    CLASS_TAG *operator()()                         \
  173.     {                                    \
  174.       if (current)                             \
  175.     {                                 \
  176.       GenItem(CLASS_TAG) *tmp = current;                 \
  177.       current = current->next;                     \
  178.       return &tmp->item;                         \
  179.     }                                 \
  180.       return NULL;                             \
  181.     }                                    \
  182.                 
  183.  
  184. /*
  185.  * macro that create all the generic types
  186.  * provided for ease of uses
  187.  *
  188.  * for some unknown reason my compiler can't handle a 
  189.  * function prameter that is a pointer to a member function
  190.  * It can deal with it if the pointer is declared using 
  191.  * a typedef
  192.  */
  193. #define DeclareList(CLASS_TAG)     \
  194.   typedef int (CLASS_TAG::*PTAMF(CLASS_TAG))(CLASS_TAG &); \
  195.   class GenList(CLASS_TAG);     \
  196.   class GenIter(CLASS_TAG);     \
  197.   declare(GenItem,CLASS_TAG);     \
  198.   declare(GenList,CLASS_TAG);    \
  199.   declare(GenIter,CLASS_TAG)
  200.  
  201. #endif
  202.  
  203.  
  204.  
  205.  
  206. [LISTING TWO]
  207.  
  208.  
  209. /*
  210.  * test1.cc
  211.  *
  212.  * by A. E. Davidson
  213.  *
  214.  * Provides a driver to test the generic list
  215.  */
  216.  
  217. #include <stream.h>
  218. #include "coin.hh"
  219. #include "genericl.hh"
  220.  
  221. /*
  222.  * use the declare macros to 
  223.  * allow creation of list of desired types
  224.  */
  225.  
  226. DeclareList(coin);
  227.  
  228. /*
  229.  * proto typing function using the generic list
  230.  * stuff must be done after DeclareList()
  231.  */
  232. void displayAndTotal(GenIter(coin) next_coin);
  233.      
  234. main()
  235. {
  236.   /*--- create some coins -------*/
  237.   coin c1 = penny;
  238.   coin c2 = nickel;
  239.   coin c3 = dime;
  240.   coin c4 = quarter;
  241.  
  242.   /*------ create a list of coins -----*/
  243.   GenList(coin) list_of_coins;
  244.   list_of_coins.append(c1);
  245.   list_of_coins.append(c2);
  246.   list_of_coins.append(c3);
  247.   list_of_coins.append(c4);
  248.  
  249.   /*------- display the list of coins and there total ------*/
  250.   displayAndTotal(list_of_coins);
  251.  
  252.   /*-------------- remove one of the coins --------------*/
  253.   cout << "\n\n list after removing coin c2 \n";
  254.   list_of_coins.removeItem(&coin::found, c2);
  255.   displayAndTotal(list_of_coins);
  256.   
  257.  
  258.   /*
  259.    * rember: c2 has been removed from the list but it still exists
  260.    */
  261.   cout << "\n\n coin c2 still exists, it was only removed from the list \n";
  262.   cout << "coin: " << c2;
  263.  
  264.  
  265. #ifdef NEVER 
  266.  
  267.   /* 
  268.    * this is example shows a design flaw
  269.    * with the generic list assignment operator
  270.    *
  271.    * if you delete an object but do not remove it 
  272.    * from the list first you will get a core dump.
  273.    * The list will contain a dangling reference
  274.    *
  275.    * this is becuase I chose to implement the
  276.    * the list using references instead of copying
  277.    * the objects. See the discusion at the end of the
  278.    * article
  279.    */
  280.   coin *c5 = new coin(quarter);
  281.  
  282.   list_of_coins.append(*c5);
  283.   delete c5;
  284.   displayAndTotal(list_of_coins);
  285.  
  286. #endif  
  287. }
  288.  
  289. /*
  290.  * this function illustrates
  291.  * how to use the GenIter class
  292.  *
  293.  * notice that the parmeter list expect
  294.  * an inter object, but I always pass a list
  295.  * object
  296.  */
  297. void displayAndTotal(GenIter(coin) next_coin)
  298. {
  299.   double total = 0.0;
  300.   coin *tmp;
  301.   
  302.   while ((tmp = next_coin()))
  303.     {
  304.       /* 
  305.        * coins know how to convert themselves to doubles
  306.        */
  307.       total += *tmp;
  308.       /*
  309.        * coins also know how to display themselves
  310.        */
  311.       cout << "coin: " << *tmp << "\ttotal: " << total <<"\n";
  312.     }
  313. }
  314.  
  315.  
  316. [LSITING THREE]
  317.  
  318. /*
  319.  * coin class
  320.  *
  321.  * by A. E. Davidson
  322.  *
  323.  * USES
  324.  * provides a simple class that can be 
  325.  * used to illistrate the operation of
  326.  * the generic list
  327.  *
  328.  * a coin may be a penny, nickel, dime, or quarter
  329.  */
  330.  
  331. #ifndef COIN_HH
  332. #define COIN_HH
  333.  
  334. enum coin_type {penny, nickel, dime, quarter}; 
  335.  
  336.  
  337. class coin 
  338. {
  339.   coin_type unit;
  340.   double    amount;
  341.   
  342.  public:
  343.   coin()
  344.     {unit = penny; amount = 0.01;} 
  345.   coin( coin_type type);
  346.   coin(const coin &other)
  347.     {unit = other.unit; amount = other.amount;} 
  348.   ~coin(){;}
  349.   coin& operator = (const coin &other)
  350.     { unit = other.unit; amount = other.amount;} 
  351.   friend ostream& operator << (ostream &os, coin &c);
  352.   operator double () 
  353.     {return amount;} 
  354.  
  355.   /*
  356.    * this function is intended to be
  357.    * used with GenList(CLASS_TAG)::removeItem()
  358.    * I get a compile error if I try to inline this 
  359.    * function
  360.    */
  361.   int found(const coin &other);
  362. };
  363.  
  364.  
  365. #endif
  366.  
  367.  
  368. [LISTING FOUR]
  369.  
  370.  
  371. #include "stream.h"
  372. #include "coin.hh"
  373.  
  374. char *coin_name[] = {"penny", "nickel", "dime", "quarter"} ; 
  375.  
  376. /*
  377.  * convenient look up table
  378.  * keeps from having to duplicate case statements any
  379.  * time you need to work with unit data member
  380.  */
  381. static struct 
  382. {
  383.   coin_type  kind;
  384.   double     amount;
  385. } table [] =
  386.     {
  387.       {penny,   0.01},
  388.       {nickel,  0.05},
  389.       {dime,    0.10},
  390.       {quarter, 0.25},
  391.       {quarter, 0.0},        /* end of the table */
  392.     };
  393.  
  394. coin::coin(coin_type type)
  395. {
  396.   unit = type;
  397.   for (int i = 0; table[i].amount != 0.0 && unit != table[i].kind; i++)
  398.     ;
  399.   amount = table[i].amount;
  400. }
  401.  
  402.  
  403. ostream& operator << (ostream &os, coin &c)
  404. {
  405.   os << coin_name[c.unit];
  406.   return os;
  407. }
  408.  
  409.  
  410. int coin::found(const coin &other)
  411. {
  412.   return (unit == other.unit);
  413. }
  414.  
  415.   
  416.  
  417. [LISTING FIVE]
  418.  
  419.  
  420. /*
  421.  * this is the output from CPP
  422.  * g++ -E test1.cc
  423.  *
  424.  * I reformated the output to make it 
  425.  * easier to read
  426.  */
  427.  
  428. typedef int (coin::*  coinPTAMF   )(coin &); 
  429. class coinGenList   ; 
  430. class coinGenIter   ;  
  431.       
  432. class coinGenItem    
  433.   coinGenItem    *next; 
  434.   coin &item; 
  435.  
  436.   coinGenItem   (coin &i) : item(i)    
  437.     {next = 0 ;} 
  438.   coinGenItem   (coin &i, coinGenItem    *n) : item(i) 
  439.     {next = n; } ~coinGenItem   () 
  440.       {;}    
  441.   friend coinGenList   ; 
  442.   friend coinGenIter   ; 
  443. }     ;        
  444.  
  445. class coinGenList       
  446. {    
  447.   coinGenItem    *hd;    
  448.  
  449.  public:    
  450.   coinGenList   (coinGenItem    *n = 0 )    
  451.     { hd = n;} 
  452.   coinGenList   (const coin &i) 
  453.     {hd = 0 ; insert(i);} 
  454.   ~coinGenList   ()    
  455.     {Clear();}    
  456.   void Clear(void)    
  457.     {    
  458.       coinGenItem    *pt;    
  459.  
  460.       while (hd)    
  461.     {    
  462.       pt = hd;    
  463.       hd = hd->next;    
  464.       delete pt;    
  465.     }    
  466.     }    
  467.   coinGenList   (const coinGenList    &seq) 
  468.     {hd = seq.hd;} 
  469.   coinGenList    operator = (const coinGenList    &other)    
  470.     {    hd = other.hd; return *this;    }    
  471.   void insert(coin &i)
  472.     { hd = new coinGenItem   (i, hd); } 
  473.   void append(coin &i)    
  474.     {    
  475.       for (coinGenItem    *pt = hd; pt && pt ->next; pt = pt->next)    
  476.     ;    
  477.       if (pt) 
  478.     {    
  479.       coinGenItem    *tmp = new coinGenItem   (i); 
  480.       pt->next = tmp;    
  481.     } 
  482.       else 
  483.     insert(i);    
  484.     } 
  485.   void removeItem(  coinPTAMF    found, coin &obj) 
  486.     {    
  487.       coinGenItem    *prev, *rem;    
  488.  
  489.       prev = 0 ;    
  490.       rem = hd;    
  491.       while( rem && !(obj.*found)(rem->item) )    
  492.     {    
  493.       prev = rem;    
  494.       rem = rem->next;    
  495.     }    
  496.       if (rem) 
  497.     {    
  498.       if (prev)    
  499.         prev->next = rem->next;    
  500.       else    
  501.         hd = rem->next;    
  502.       delete rem;    
  503.     }    
  504.     }    
  505.   friend coinGenIter   ;    
  506. }  ;           
  507.  
  508. class coinGenIter    
  509.   coinGenItem    *current;    
  510.  
  511.  public: 
  512.   coinGenIter   (coinGenList    &ilist)    
  513.     { current = ilist.hd; }    
  514.   coinGenIter   (coinGenIter    &other)    
  515.     { current = other.current; } 
  516.   ~coinGenIter   () {;} 
  517.   coinGenIter    operator = (coinGenList    &ilist) 
  518.     { current = ilist.hd; return *this; } 
  519.   coin *operator()() 
  520.     {    
  521.       if (current) 
  522.     { 
  523.       coinGenItem    *tmp = current; 
  524.       current = current->next; 
  525.       return &tmp->item; 
  526.     } return 0 ; 
  527.     }    
  528. }   ;
  529.  
  530.  
  531.  
  532.  
  533.  
  534. void displayAndTotal(coinGenIter    next_coin);
  535.      
  536. main()
  537. {
  538.    
  539.   coin c1 = penny;
  540.   coin c2 = nickel;
  541.   coin c3 = dime;
  542.   coin c4 = quarter;
  543.  
  544.    
  545.   coinGenList    list_of_coins;
  546.   list_of_coins.append(c1);
  547.   list_of_coins.append(c2);
  548.   list_of_coins.append(c3);
  549.   list_of_coins.append(c4);
  550.  
  551.    
  552.   displayAndTotal(list_of_coins);
  553.  
  554.    
  555.   cout << "\n\n list after removing coin c2 \n";
  556.   list_of_coins.removeItem(&coin::found, c2);
  557.   displayAndTotal(list_of_coins);
  558.   
  559.  
  560.    
  561.  
  562.  
  563.   cout << "\n\n coin c2 still exists, it was only removed from the list \n";
  564.   cout << "coin: " << c2;
  565.  
  566.  
  567. # 78 "test1.cc"
  568.  
  569. }
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579. void displayAndTotal(coinGenIter    next_coin)
  580. {
  581.   double total = 0.0;
  582.   coin *tmp;
  583.   
  584.   while ((tmp = next_coin()))
  585.     {
  586.        
  587.  
  588.  
  589.       total += *tmp;
  590.        
  591.  
  592.  
  593.       cout << "coin: " << *tmp << "\ttotal: " << total <<"\n";
  594.     }
  595. }
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603. [MAKEFILE]
  604.  
  605. CC=     g++
  606. OBJS=    coin.o test1.o
  607. SRCS = coin.cc test1.cc
  608. LIBS=     -lg++ -lm
  609. INCLUDE= -I/n/catserv/usr1/tools/sun4/usr/local/lib/g++-include
  610.  
  611. .SUFFIXES: .cc
  612.  
  613. .cc.o: 
  614.     $(CC) -c -g $<
  615.  
  616. coinTest : $(OBJS) coin.hh genericlt.hh
  617.     $(CC) -o $@ -g $(OBJS) $(LIBS)
  618.  
  619. clean :
  620.     rm -f coinTest *.o
  621.  
  622.  
  623. #
  624. # notes
  625. #
  626.  
  627. #
  628. #  $@ the name of the current target
  629. #
  630.  
  631. #
  632. # $< the name of a dependency file, derived as if selected
  633. # for use with an implicit rule
  634. #
  635.  
  636. depend : 
  637.     makedepend -- $(CFLAGS) -- $(INCLUDE) -- $(SRCS)
  638. # DO NOT DELETE THIS LINE -- make depend depends on it.
  639.  
  640. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stream.h
  641. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/ostream.h
  642. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/File.h
  643. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/builtin.h
  644. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stddef.h
  645. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/std.h
  646. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stdio.h
  647. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/math.h
  648. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/values.h
  649. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/streambuf.h
  650. coin.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/istream.h
  651. coin.o: coin.hh
  652. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stream.h
  653. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/ostream.h
  654. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/File.h
  655. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/builtin.h
  656. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stddef.h
  657. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/std.h
  658. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/stdio.h
  659. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/math.h
  660. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/values.h
  661. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/streambuf.h
  662. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/istream.h
  663. test1.o: coin.hh genericlt.hh
  664. test1.o: /n/catserv/usr1/tools/sun4/usr/local/lib/g++-include/generic.h
  665.